package main

import (
	"encoding/json"
	"log"
	"net"
	"net/http"
	"time"
)

const (
	// TextMessage denotes a text data message. The text message payload is
	// interpreted as UTF-8 encoded text data.
	TextMessage = 1

	// BinaryMessage denotes a binary data message.
	BinaryMessage = 2

	// CloseMessage denotes a close control message. The optional message
	// payload contains a numeric code and text. Use the FormatCloseMessage
	// function to format a close message payload.
	CloseMessage = 8

	// PingMessage denotes a ping control message. The optional message payload
	// is UTF-8 encoded text.
	PingMessage = 9

	// PongMessage denotes a pong control message. The optional message payload
	// is UTF-8 encoded text.
	PongMessage = 10

	PingWait = 30
)

type WsHandler func(conn *WsConn)

type Message struct {
	Typ     int
	context []byte
}

type WsConn struct {
	Conn         net.Conn
	pingHandler  WsHandler
	pongHandler  WsHandler
	CloseHandler WsHandler
}

func main() {

}

func NewHandler(w http.ResponseWriter, req *http.Request) *WsConn {

	hijacker, ok := w.(http.Hijacker)
	if !ok {
		log.Println("ws conn create err")
		return nil
	}
	conn, _, err := hijacker.Hijack()
	if err != nil {
		log.Println("未能拦截tcp")
		return nil
	}
	//w.Header().Set("Upgrader", )
	wsConn := WsConn{
		Conn: conn,
		pingHandler: func(conn *WsConn) {
			conn.Conn.SetWriteDeadline(time.Now().Add(PingWait * time.Second))
		},
		pongHandler: func(conn *WsConn) {
			conn.Conn.SetReadDeadline(time.Now().Add(PingWait * time.Second))
		},
		CloseHandler: func(conn *WsConn) {
			conn.Conn.Close()
		},
	}
	return &wsConn
}

func (conn *WsConn) ReadMsg(b []byte) error {
	defer conn.pongHandler(conn)
	var msg Message
	conn.Conn.Read(b)
	err := json.Unmarshal(b, &msg)
	if err != nil {
		log.Println(err)
		return err
	}

	return nil
}

func (conn *WsConn) WriteMsg(msg Message) error {
	defer conn.pongHandler(conn)
	if msg.Typ == PingMessage {
		marshal, _ := json.Marshal(msg)
		_, err := conn.Conn.Write(marshal)
		if err != nil {
			log.Println("WritePingErr")
			return err
		}
	} else if msg.Typ == PongMessage {
		marshal, _ := json.Marshal(msg)
		_, err := conn.Conn.Write(marshal)
		if err != nil {
			log.Println("WritePingErr")
			return err
		}
	} else if msg.Typ == TextMessage {
		marshal, _ := json.Marshal(msg)
		_, err := conn.Conn.Write(marshal)
		if err != nil {
			log.Println("WritePingErr")
			return err
		}
	}
	return nil
}
